package com.neural.infrastructure;

import java.util.ArrayList;
import java.util.List;

import javax.management.RuntimeErrorException;

import com.neural.activation.Activation;
import com.neural.activation.ActivationManager;
import com.neural.descriptor.LayerDescriptor;
import com.neural.descriptor.NeuronDescriptor;
import com.neural.randomizer.Randomizer;

public class Layer {
 
	private final Activation activationMethod;
	private final List<Neuron> neurons;
	private final Randomizer randomizer;

	public Layer(LayerDescriptor layerDescriptor, Layer previousLayer) {
		this.randomizer = new Randomizer(layerDescriptor.getRange(), 100);
		this.activationMethod = ActivationManager.getActivationFromName(layerDescriptor.getActivationMethod());
		this.neurons = createNeurons(layerDescriptor.getNeuronsDescriptor(), previousLayer, randomizer);
	}
	
	private List<Neuron> createNeurons(List<NeuronDescriptor> neuronDescriptors, Layer previousLayer, Randomizer randomizer) {
		List<Neuron> neurons = new ArrayList<Neuron>(neuronDescriptors.size());
		for (NeuronDescriptor neuronDescriptor : neuronDescriptors) {
			Neuron neuron = new Neuron(neuronDescriptor, previousLayer, randomizer);
			neurons.add(neuron);
		}
		return neurons;
	}
	
	public Activation getActivationMethod() {
		return activationMethod;
	}
	
	public List<Neuron> getNeurons() {
		return neurons;
	}
	
	public void setNeuronValues(List<Double> inputs) {
		if(inputs.size() != neurons.size()) {
			throw new RuntimeErrorException(new Error());
		}
		for(int i = 0; i < inputs.size(); i++) {
			neurons.get(i).setValue(inputs.get(i));
		}
	}
	
	public void compute() {
		for(Neuron neuron : neurons) {
			neuron.compute(activationMethod);
		}
	}
	
	public List<Double> getValues() {

		List<Double> values = new ArrayList<Double>(neurons.size());
		for(int i = 0; i < neurons.size(); i++) {
			values.add(neurons.get(i).getValue());
		}
		return values;
	}
}
